@levischuck/tiny-html 0.0.4 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
- import { ParseResult, HtmlNode, WriterOptions } from './types.ts';
1
+ import { ParseResult, HtmlNode, WriterOptions, SafeHtmlOptions, ParserOptions } from './types.ts';
2
2
  /**
3
3
  * Parses HTML string into a ParseResult containing HtmlNode
4
+ * @param html - The HTML string to parse
5
+ * @param options - Parser options including attributeNaming ('reactName' or 'exactName')
4
6
  */
5
- export declare function readHtml(html: string): ParseResult;
7
+ export declare function readHtml(html: string, options?: ParserOptions): ParseResult;
6
8
  /**
7
9
  * Renders HtmlNode or ParseResult to HTML string
8
10
  */
@@ -12,8 +14,17 @@ export declare function writeHtml(input: HtmlNode | ParseResult, options?: Write
12
14
  * Returns a new HtmlNode with all promises resolved
13
15
  */
14
16
  export declare function awaitHtmlNode(node: HtmlNode | Promise<HtmlNode>): Promise<HtmlNode>;
17
+ /**
18
+ * Sanitizes an HtmlNode tree by removing disallowed tags, attributes, and URLs.
19
+ * - Tags not in allowedTags have their content retained (folded into parent)
20
+ * - Images replaced with their alt text when removed
21
+ * - Attributes not in the tag's allowed list are dropped
22
+ * - Classes are filtered by allowedClasses patterns (supports wildcards)
23
+ * - URLs not matching allowedLinkProtocols cause the element to be removed
24
+ */
25
+ export declare function safeHtml(node: HtmlNode, options?: SafeHtmlOptions): HtmlNode;
15
26
  export { htmlNodeTo } from './convert.ts';
16
27
  export { decodeHtmlEntities, encodeHtmlEntities } from './entities.ts';
17
28
  export type { CreateElementFn, CreateElementProps } from './convert.ts';
18
29
  export { getTextContent } from './writer.ts';
19
- export type { WriterOptions, ParseResult, HtmlNode, HtmlElement, HtmlProps, HtmlStyle } from './types.ts';
30
+ export type { WriterOptions, ParseResult, HtmlNode, HtmlElement, HtmlProps, HtmlStyle, SafeHtmlOptions, AllowedTag, ParserOptions, ParserAttributeNaming, WriterAttributeNaming, } from './types.ts';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- const F = /* @__PURE__ */ new Set([
1
+ const $ = /* @__PURE__ */ new Set([
2
2
  "area",
3
3
  "base",
4
4
  "br",
@@ -13,7 +13,7 @@ const F = /* @__PURE__ */ new Set([
13
13
  "source",
14
14
  "track",
15
15
  "wbr"
16
- ]), Q = /* @__PURE__ */ new Set([
16
+ ]), K = /* @__PURE__ */ new Set([
17
17
  // Containers
18
18
  "div",
19
19
  "span",
@@ -110,7 +110,7 @@ const F = /* @__PURE__ */ new Set([
110
110
  "body",
111
111
  "title",
112
112
  "meta"
113
- ]), q = /* @__PURE__ */ new Map([
113
+ ]), H = /* @__PURE__ */ new Map([
114
114
  ["p", /* @__PURE__ */ new Set(["p"])],
115
115
  ["li", /* @__PURE__ */ new Set(["li"])],
116
116
  ["dt", /* @__PURE__ */ new Set(["dt", "dd"])],
@@ -123,7 +123,7 @@ const F = /* @__PURE__ */ new Set([
123
123
  ["tr", /* @__PURE__ */ new Set(["tr"])],
124
124
  ["td", /* @__PURE__ */ new Set(["td", "th"])],
125
125
  ["th", /* @__PURE__ */ new Set(["td", "th"])]
126
- ]), V = /* @__PURE__ */ new Map([
126
+ ]), B = /* @__PURE__ */ new Map([
127
127
  ["altglyph", "altGlyph"],
128
128
  ["altglyphdef", "altGlyphDef"],
129
129
  ["altglyphitem", "altGlyphItem"],
@@ -161,7 +161,7 @@ const F = /* @__PURE__ */ new Set([
161
161
  ["lineargradient", "linearGradient"],
162
162
  ["radialgradient", "radialGradient"],
163
163
  ["textpath", "textPath"]
164
- ]), z = /* @__PURE__ */ new Map([
164
+ ]), V = /* @__PURE__ */ new Map([
165
165
  ["attributename", "attributeName"],
166
166
  ["attributetype", "attributeType"],
167
167
  ["basefrequency", "baseFrequency"],
@@ -220,7 +220,7 @@ const F = /* @__PURE__ */ new Set([
220
220
  ["xchannelselector", "xChannelSelector"],
221
221
  ["ychannelselector", "yChannelSelector"],
222
222
  ["zoomandpan", "zoomAndPan"]
223
- ]), I = {
223
+ ]), P = {
224
224
  lt: "<",
225
225
  gt: ">",
226
226
  amp: "&",
@@ -291,44 +291,44 @@ const F = /* @__PURE__ */ new Set([
291
291
  rArr: "⇒",
292
292
  dArr: "⇓",
293
293
  hArr: "⇔"
294
- }, B = {};
295
- for (const [e, n] of Object.entries(I))
296
- B[n] || (B[n] = e);
297
- function w(e) {
298
- return !e || typeof e != "string" || !e.includes("&") ? e : e.replace(/&(?:#[xX]([0-9a-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z0-9]*));/g, (n, r, l, a) => {
299
- if (r) {
300
- const o = parseInt(r, 16);
301
- return String.fromCodePoint(o);
294
+ }, W = {};
295
+ for (const [e, t] of Object.entries(P))
296
+ W[t] || (W[t] = e);
297
+ function O(e) {
298
+ return !e || typeof e != "string" || !e.includes("&") ? e : e.replace(/&(?:#[xX]([0-9a-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z0-9]*));/g, (t, i, l, s) => {
299
+ if (i) {
300
+ const a = parseInt(i, 16);
301
+ return String.fromCodePoint(a);
302
302
  } else if (l) {
303
- const o = parseInt(l, 10);
304
- return String.fromCodePoint(o);
305
- } else if (a && I[a])
306
- return I[a];
307
- return n;
303
+ const a = parseInt(l, 10);
304
+ return String.fromCodePoint(a);
305
+ } else if (s && P[s])
306
+ return P[s];
307
+ return t;
308
308
  });
309
309
  }
310
- function x(e, n = !1) {
310
+ function G(e, t = !1) {
311
311
  if (!e || typeof e != "string")
312
312
  return e;
313
- let r = e;
314
- return r = r.replace(/&/g, "&amp;"), r = r.replace(/</g, "&lt;"), r = r.replace(/>/g, "&gt;"), n && (r = r.replace(/"/g, "&quot;")), r;
313
+ let i = e;
314
+ return i = i.replace(/&/g, "&amp;"), i = i.replace(/</g, "&lt;"), i = i.replace(/>/g, "&gt;"), t && (i = i.replace(/"/g, "&quot;")), i;
315
315
  }
316
- function Z(e) {
316
+ function J(e) {
317
317
  return e.replace(/\]\]>/g, "]]]]><![CDATA[>");
318
318
  }
319
- function k(e) {
320
- return e.replace(/[-_]([a-z])/g, (n, r) => r.toUpperCase());
319
+ function Z(e) {
320
+ return e.replace(/[-_]([a-z])/g, (t, i) => i.toUpperCase());
321
321
  }
322
- function $(e) {
323
- return e.replace(/[A-Z]/g, (n) => `-${n.toLowerCase()}`);
322
+ function ee(e) {
323
+ return e.replace(/[A-Z]/g, (t) => `-${t.toLowerCase()}`);
324
324
  }
325
- function d(e, n, r) {
326
- return new TextDecoder("utf-8").decode(e.slice(n, r));
325
+ function b(e, t, i) {
326
+ return new TextDecoder("utf-8").decode(e.slice(t, i));
327
327
  }
328
- function S(e) {
328
+ function C(e) {
329
329
  return e === 32 || e === 9 || e === 10 || e === 13;
330
330
  }
331
- function N(e) {
331
+ function S(e) {
332
332
  return e >= 97 && e <= 122 || // a-z
333
333
  e >= 65 && e <= 90 || // A-Z
334
334
  e >= 48 && e <= 57 || // 0-9
@@ -336,419 +336,604 @@ function N(e) {
336
336
  e === 95 || // _
337
337
  e === 58;
338
338
  }
339
- function K(e) {
340
- const r = new TextEncoder().encode(e), l = {
339
+ function te(e, t = {}) {
340
+ const i = t.attributeNaming ?? "reactName", s = new TextEncoder().encode(e), a = {
341
341
  node: []
342
- }, a = [], o = [];
343
- let u = "HTML", i = "TEXT", t = 0, c = 0, y = 0, A = 0, b = 0, g = "", P = 0, h = null;
344
- function M() {
345
- return o.length > 0 ? o[o.length - 1].children : a;
342
+ }, p = [], o = [];
343
+ let T = "HTML", n = "TEXT", r = 0, h = 0, g = 0, E = 0, N = 0, y = "", q = 0, d = null;
344
+ function x() {
345
+ return o.length > 0 ? o[o.length - 1].children : p;
346
346
  }
347
- function X(s, f) {
348
- if (s >= f) return;
349
- const p = d(r, s, f), T = w(p);
350
- T.length > 0 && M().push(T);
347
+ function D(f, c) {
348
+ if (f >= c) return;
349
+ const u = b(s, f, c), m = O(u);
350
+ m.length > 0 && x().push(m);
351
351
  }
352
- function U(s, f) {
353
- if (s >= f) return;
354
- const p = d(r, s, f);
355
- p.length > 0 && M().push(p);
352
+ function M(f, c) {
353
+ if (f >= c) return;
354
+ const u = b(s, f, c);
355
+ u.length > 0 && x().push(u);
356
356
  }
357
- function C(s, f) {
358
- const p = s.toLowerCase();
359
- return f === "SVG" && V.has(p) ? V.get(p) : p;
357
+ function v(f, c) {
358
+ const u = f.toLowerCase();
359
+ return c === "SVG" && B.has(u) ? B.get(u) : u;
360
360
  }
361
- function _(s, f) {
362
- const p = s.toLowerCase();
363
- if (p === "class") return "className";
364
- if (p === "for") return "htmlFor";
365
- if (f === "SVG")
366
- return z.has(p) ? z.get(p) : s;
367
- if (f === "HTML") {
368
- const T = k(p);
369
- return p === "class" || p === "for" ? p === "class" ? "className" : "htmlFor" : T;
370
- }
371
- return p;
361
+ function L(f, c) {
362
+ const u = f.toLowerCase();
363
+ return u === "class" ? i === "exactName" ? "class" : "className" : u === "for" ? i === "exactName" ? "for" : "htmlFor" : c === "SVG" ? V.has(u) ? V.get(u) : f : c === "HTML" ? Z(u) : u;
372
364
  }
373
- function R(s) {
374
- const f = C(s, u);
375
- for (let p = o.length - 1; p >= 0; p--)
376
- if (o[p].type === f) {
377
- for (let T = o.length - 1; T >= p; T--) {
378
- const m = o.pop(), E = {
379
- type: m.type,
365
+ function I(f) {
366
+ const c = v(f, T);
367
+ for (let u = o.length - 1; u >= 0; u--)
368
+ if (o[u].type === c) {
369
+ for (let m = o.length - 1; m >= u; m--) {
370
+ const A = o.pop(), w = {
371
+ type: A.type,
380
372
  props: {
381
- ...m.props,
382
- children: m.children.length === 1 ? m.children[0] : m.children
373
+ ...A.props,
374
+ children: A.children.length === 1 ? A.children[0] : A.children
383
375
  }
384
376
  };
385
- o.length > 0 ? o[o.length - 1].children.push(E) : a.push(E), (m.type === "svg" || m.type === "math") && (u = "HTML");
377
+ o.length > 0 ? o[o.length - 1].children.push(w) : p.push(w), (A.type === "svg" || A.type === "math") && (T = "HTML");
386
378
  }
387
379
  return;
388
380
  }
389
381
  }
390
- function v(s, f, p) {
391
- const T = C(s, u);
392
- if (o.length > 0 && q.has(T)) {
393
- const E = q.get(T), j = o[o.length - 1].type;
394
- E.has(j) && R(j);
382
+ function _(f, c, u) {
383
+ const m = v(f, T);
384
+ if (o.length > 0 && H.has(m)) {
385
+ const w = H.get(m), z = o[o.length - 1].type;
386
+ w.has(z) && I(z);
395
387
  }
396
- let m = u;
397
- if (T === "svg" ? m = "SVG" : T === "math" && (m = "MATHML"), F.has(T) || p) {
398
- const E = {
399
- type: T,
400
- props: f
388
+ let A = T;
389
+ if (m === "svg" ? A = "SVG" : m === "math" && (A = "MATHML"), $.has(m) || u) {
390
+ const w = {
391
+ type: m,
392
+ props: c
401
393
  };
402
- M().push(E);
394
+ x().push(w);
403
395
  } else {
404
- const E = {
405
- type: T,
406
- props: f,
396
+ const w = {
397
+ type: m,
398
+ props: c,
407
399
  children: [],
408
- namespace: m
400
+ namespace: A
409
401
  };
410
- o.push(E), u = m;
402
+ o.push(w), T = A;
411
403
  }
412
404
  }
413
- for (; t < r.length; ) {
414
- const s = r[t];
415
- switch (i) {
405
+ for (; r < s.length; ) {
406
+ const f = s[r];
407
+ switch (n) {
416
408
  case "TEXT":
417
- s === 60 && (X(c, t), i = "TAG_OPEN"), t++;
409
+ f === 60 && (D(h, r), n = "TAG_OPEN"), r++;
418
410
  break;
419
411
  case "TAG_OPEN":
420
- s === 33 ? r[t + 1] === 45 && r[t + 2] === 45 ? (i = "COMMENT", t += 3) : r[t + 1] === 68 || r[t + 1] === 100 ? d(r, t, Math.min(t + 20, r.length)).toLowerCase().startsWith("!doctype") ? (i = "DOCTYPE", y = t, t++) : (c = t - 1, i = "TEXT") : r[t + 1] === 91 && r[t + 2] === 67 && d(r, t, Math.min(t + 9, r.length)).startsWith("![CDATA[") ? (i = "CDATA", c = t + 8, t += 8) : (c = t - 1, i = "TEXT") : s === 63 ? (i = "PROCESSING_INSTRUCTION", y = t - 1, t++) : s === 47 ? (i = "TAG_CLOSE_START", t++) : N(s) ? (y = t, i = "TAG_NAME", h = null, t++) : (c = t - 1, i = "TEXT");
412
+ f === 33 ? s[r + 1] === 45 && s[r + 2] === 45 ? (n = "COMMENT", r += 3) : s[r + 1] === 68 || s[r + 1] === 100 ? b(s, r, Math.min(r + 20, s.length)).toLowerCase().startsWith("!doctype") ? (n = "DOCTYPE", g = r, r++) : (h = r - 1, n = "TEXT") : s[r + 1] === 91 && s[r + 2] === 67 && b(s, r, Math.min(r + 9, s.length)).startsWith("![CDATA[") ? (n = "CDATA", h = r + 8, r += 8) : (h = r - 1, n = "TEXT") : f === 63 ? (n = "PROCESSING_INSTRUCTION", g = r - 1, r++) : f === 47 ? (n = "TAG_CLOSE_START", r++) : S(f) ? (g = r, n = "TAG_NAME", d = null, r++) : (h = r - 1, n = "TEXT");
421
413
  break;
422
414
  case "TAG_NAME":
423
- if (S(s)) {
424
- const f = d(r, y, t), p = f.toLowerCase();
425
- h = {
426
- type: f,
415
+ if (C(f)) {
416
+ const c = b(s, g, r), u = c.toLowerCase();
417
+ d = {
418
+ type: c,
427
419
  props: {},
428
420
  children: [],
429
- namespace: p === "svg" ? "SVG" : p === "math" ? "MATHML" : u
430
- }, i = "ATTRIBUTES", t++;
431
- } else if (s === 62) {
432
- const f = d(r, y, t);
433
- v(f, {}, !1);
434
- const p = C(f, u);
435
- p === "script" ? (i = "SCRIPT_CONTENT", c = t + 1) : p === "style" ? (i = "STYLE_CONTENT", c = t + 1) : (i = "TEXT", c = t + 1), t++;
436
- } else s === 47 ? (i = "TAG_CLOSE_SELF", t++) : N(s) ? t++ : (c = y - 1, i = "TEXT");
421
+ namespace: u === "svg" ? "SVG" : u === "math" ? "MATHML" : T
422
+ }, n = "ATTRIBUTES", r++;
423
+ } else if (f === 62) {
424
+ const c = b(s, g, r);
425
+ _(c, {}, !1);
426
+ const u = v(c, T);
427
+ u === "script" ? (n = "SCRIPT_CONTENT", h = r + 1) : u === "style" ? (n = "STYLE_CONTENT", h = r + 1) : (n = "TEXT", h = r + 1), r++;
428
+ } else f === 47 ? (n = "TAG_CLOSE_SELF", r++) : S(f) ? r++ : (h = g - 1, n = "TEXT");
437
429
  break;
438
430
  case "ATTRIBUTES":
439
- if (S(s))
440
- t++;
441
- else if (s === 62) {
442
- const f = h.type;
443
- v(f, h.props, !1);
444
- const p = C(f, u);
445
- p === "script" ? (i = "SCRIPT_CONTENT", c = t + 1) : p === "style" ? (i = "STYLE_CONTENT", c = t + 1) : (i = "TEXT", c = t + 1), t++;
446
- } else s === 47 ? (i = "TAG_CLOSE_SELF", t++) : N(s) ? (A = t, i = "ATTRIBUTE_NAME", t++) : (c = y - 1, i = "TEXT");
431
+ if (C(f))
432
+ r++;
433
+ else if (f === 62) {
434
+ const c = d.type;
435
+ _(c, d.props, !1);
436
+ const u = v(c, T);
437
+ u === "script" ? (n = "SCRIPT_CONTENT", h = r + 1) : u === "style" ? (n = "STYLE_CONTENT", h = r + 1) : (n = "TEXT", h = r + 1), r++;
438
+ } else f === 47 ? (n = "TAG_CLOSE_SELF", r++) : S(f) ? (E = r, n = "ATTRIBUTE_NAME", r++) : (h = g - 1, n = "TEXT");
447
439
  break;
448
440
  case "ATTRIBUTE_NAME":
449
- if (S(s)) {
450
- g = d(r, A, t);
451
- const f = _(g, h.namespace);
452
- h.props[f] = !0, g = "", i = "ATTRIBUTES", t++;
453
- } else if (s === 61)
454
- g = d(r, A, t), i = "ATTRIBUTE_VALUE_START", t++;
455
- else if (s === 62) {
456
- g = d(r, A, t);
457
- const f = _(g, h.namespace);
458
- h.props[f] = !0, g = "";
459
- const p = h.type;
460
- v(p, h.props, !1);
461
- const T = C(p, u);
462
- T === "script" ? (i = "SCRIPT_CONTENT", c = t + 1) : T === "style" ? (i = "STYLE_CONTENT", c = t + 1) : (i = "TEXT", c = t + 1), t++;
463
- } else if (s === 47) {
464
- g = d(r, A, t);
465
- const f = _(g, h.namespace);
466
- h.props[f] = !0, g = "", i = "TAG_CLOSE_SELF", t++;
467
- } else N(s) ? t++ : (c = y - 1, i = "TEXT");
441
+ if (C(f)) {
442
+ y = b(s, E, r);
443
+ const c = L(y, d.namespace);
444
+ d.props[c] = !0, y = "", n = "ATTRIBUTES", r++;
445
+ } else if (f === 61)
446
+ y = b(s, E, r), n = "ATTRIBUTE_VALUE_START", r++;
447
+ else if (f === 62) {
448
+ y = b(s, E, r);
449
+ const c = L(y, d.namespace);
450
+ d.props[c] = !0, y = "";
451
+ const u = d.type;
452
+ _(u, d.props, !1);
453
+ const m = v(u, T);
454
+ m === "script" ? (n = "SCRIPT_CONTENT", h = r + 1) : m === "style" ? (n = "STYLE_CONTENT", h = r + 1) : (n = "TEXT", h = r + 1), r++;
455
+ } else if (f === 47) {
456
+ y = b(s, E, r);
457
+ const c = L(y, d.namespace);
458
+ d.props[c] = !0, y = "", n = "TAG_CLOSE_SELF", r++;
459
+ } else S(f) ? r++ : (h = g - 1, n = "TEXT");
468
460
  break;
469
461
  case "ATTRIBUTE_VALUE_START":
470
- S(s) ? t++ : s === 34 || s === 39 ? (P = s, b = t + 1, i = "ATTRIBUTE_VALUE_QUOTED", t++) : (b = t, i = "ATTRIBUTE_VALUE_UNQUOTED");
462
+ C(f) ? r++ : f === 34 || f === 39 ? (q = f, N = r + 1, n = "ATTRIBUTE_VALUE_QUOTED", r++) : (N = r, n = "ATTRIBUTE_VALUE_UNQUOTED");
471
463
  break;
472
464
  case "ATTRIBUTE_VALUE_QUOTED":
473
- if (s === P) {
474
- const f = d(r, b, t), p = w(f), T = _(g, h.namespace);
475
- T === "style" ? h.props[T] = D(p) : h.props[T] = p, g = "", i = "ATTRIBUTES", t++;
465
+ if (f === q) {
466
+ const c = b(s, N, r), u = O(c), m = L(y, d.namespace);
467
+ m === "style" ? d.props[m] = F(u) : d.props[m] = u, y = "", n = "ATTRIBUTES", r++;
476
468
  } else
477
- t++;
469
+ r++;
478
470
  break;
479
471
  case "ATTRIBUTE_VALUE_UNQUOTED":
480
- if (S(s) || s === 62 || s === 47) {
481
- const f = d(r, b, t), p = w(f), T = _(g, h.namespace);
482
- T === "style" ? h.props[T] = D(p) : h.props[T] = p, g = "", i = "ATTRIBUTES";
472
+ if (C(f) || f === 62 || f === 47) {
473
+ const c = b(s, N, r), u = O(c), m = L(y, d.namespace);
474
+ m === "style" ? d.props[m] = F(u) : d.props[m] = u, y = "", n = "ATTRIBUTES";
483
475
  } else
484
- t++;
476
+ r++;
485
477
  break;
486
478
  case "TAG_CLOSE_SELF":
487
- if (s === 62) {
488
- const f = h.type;
489
- v(f, h.props, !0), i = "TEXT", c = t + 1, t++;
479
+ if (f === 62) {
480
+ const c = d.type;
481
+ _(c, d.props, !0), n = "TEXT", h = r + 1, r++;
490
482
  } else
491
- c = y - 1, i = "TEXT";
483
+ h = g - 1, n = "TEXT";
492
484
  break;
493
485
  case "TAG_CLOSE_START":
494
- N(s) ? (y = t, i = "TAG_CLOSE_NAME", t++) : (c = t - 2, i = "TEXT");
486
+ S(f) ? (g = r, n = "TAG_CLOSE_NAME", r++) : (h = r - 2, n = "TEXT");
495
487
  break;
496
488
  case "TAG_CLOSE_NAME":
497
- if (s === 62) {
498
- const f = d(r, y, t);
499
- R(f), i = "TEXT", c = t + 1, t++;
500
- } else S(s) || N(s) ? t++ : (c = y - 2, i = "TEXT");
489
+ if (f === 62) {
490
+ const c = b(s, g, r);
491
+ I(c), n = "TEXT", h = r + 1, r++;
492
+ } else C(f) || S(f) ? r++ : (h = g - 2, n = "TEXT");
501
493
  break;
502
494
  case "COMMENT":
503
- s === 45 && r[t + 1] === 45 && r[t + 2] === 62 ? (i = "TEXT", c = t + 3, t += 3) : t++;
495
+ f === 45 && s[r + 1] === 45 && s[r + 2] === 62 ? (n = "TEXT", h = r + 3, r += 3) : r++;
504
496
  break;
505
497
  case "DOCTYPE":
506
- if (s === 62) {
507
- const f = d(r, y, t + 1);
508
- l.doctype = "<" + f, i = "TEXT", c = t + 1, t++;
498
+ if (f === 62) {
499
+ const c = b(s, g, r + 1);
500
+ a.doctype = "<" + c, n = "TEXT", h = r + 1, r++;
509
501
  } else
510
- t++;
502
+ r++;
511
503
  break;
512
504
  case "CDATA":
513
- s === 93 && r[t + 1] === 93 && r[t + 2] === 62 ? (U(c, t), i = "TEXT", c = t + 3, t += 3) : t++;
505
+ f === 93 && s[r + 1] === 93 && s[r + 2] === 62 ? (M(h, r), n = "TEXT", h = r + 3, r += 3) : r++;
514
506
  break;
515
507
  case "PROCESSING_INSTRUCTION":
516
- if (s === 63 && r[t + 1] === 62) {
517
- const f = d(r, y, t + 2);
518
- l.xml = f, i = "TEXT", c = t + 2, t += 2;
508
+ if (f === 63 && s[r + 1] === 62) {
509
+ const c = b(s, g, r + 2);
510
+ a.xml = c, n = "TEXT", h = r + 2, r += 2;
519
511
  } else
520
- t++;
512
+ r++;
521
513
  break;
522
514
  case "SCRIPT_CONTENT":
523
515
  case "STYLE_CONTENT":
524
- if (s === 60 && r[t + 1] === 47) {
525
- const f = i === "SCRIPT_CONTENT" ? "script" : "style", p = "</" + f, T = d(r, t, Math.min(t + p.length + 1, r.length)).toLowerCase();
526
- if (T.startsWith(p) && (T[p.length] === ">" || S(T.charCodeAt(p.length)))) {
527
- U(c, t);
528
- let m = t + p.length;
529
- for (; m < r.length && r[m] !== 62; ) m++;
530
- R(f), i = "TEXT", c = m + 1, t = m + 1;
516
+ if (f === 60 && s[r + 1] === 47) {
517
+ const c = n === "SCRIPT_CONTENT" ? "script" : "style", u = "</" + c, m = b(s, r, Math.min(r + u.length + 1, s.length)).toLowerCase();
518
+ if (m.startsWith(u) && (m[u.length] === ">" || C(m.charCodeAt(u.length)))) {
519
+ M(h, r);
520
+ let A = r + u.length;
521
+ for (; A < s.length && s[A] !== 62; ) A++;
522
+ I(c), n = "TEXT", h = A + 1, r = A + 1;
531
523
  } else
532
- t++;
524
+ r++;
533
525
  } else
534
- t++;
526
+ r++;
535
527
  break;
536
528
  default:
537
- t++;
529
+ r++;
538
530
  }
539
531
  }
540
- for (i === "TEXT" ? X(c, t) : (i === "SCRIPT_CONTENT" || i === "STYLE_CONTENT") && U(c, t); o.length > 0; ) {
541
- const s = o.pop(), f = {
542
- type: s.type,
532
+ for (n === "TEXT" ? D(h, r) : (n === "SCRIPT_CONTENT" || n === "STYLE_CONTENT") && M(h, r); o.length > 0; ) {
533
+ const f = o.pop(), c = {
534
+ type: f.type,
543
535
  props: {
544
- ...s.props,
545
- children: s.children.length === 1 ? s.children[0] : s.children
536
+ ...f.props,
537
+ children: f.children.length === 1 ? f.children[0] : f.children
546
538
  }
547
539
  };
548
- o.length > 0 ? o[o.length - 1].children.push(f) : a.push(f);
540
+ o.length > 0 ? o[o.length - 1].children.push(c) : p.push(c);
549
541
  }
550
- return a.length === 0 ? l.node = null : a.length === 1 ? l.node = a[0] : l.node = a, l;
551
- }
552
- function D(e) {
553
- const n = {}, l = w(e).split(/;(?![^(]*\))/);
554
- for (const a of l) {
555
- const o = a.indexOf(":");
556
- if (o === -1) continue;
557
- const u = a.substring(0, o).trim(), i = a.substring(o + 1).trim();
558
- u && i && (n[k(u)] = i);
542
+ return p.length === 0 ? a.node = null : p.length === 1 ? a.node = p[0] : a.node = p, a;
543
+ }
544
+ function F(e) {
545
+ const t = {}, l = O(e).split(/;(?![^(]*\))/);
546
+ for (const s of l) {
547
+ const a = s.indexOf(":");
548
+ if (a === -1) continue;
549
+ const p = s.substring(0, a).trim(), o = s.substring(a + 1).trim();
550
+ p && o && (t[Z(p)] = o);
559
551
  }
560
- return n;
552
+ return t;
553
+ }
554
+ const re = {
555
+ className: "class",
556
+ htmlFor: "for"
557
+ };
558
+ function se(e, t) {
559
+ return t === "reactName" ? e : t === "exactName" || t === "eitherName" ? re[e] ?? e : e;
561
560
  }
562
- function H(e, n = {}) {
563
- const r = [];
564
- let l, a, o;
561
+ function k(e, t = {}) {
562
+ const i = [];
563
+ let l, s, a;
565
564
  if (e && typeof e == "object" && "node" in e) {
566
- const c = e;
567
- l = c.node, a = c.xml ?? n.xml, o = c.doctype ?? n.doctype;
565
+ const r = e;
566
+ l = r.node, s = r.xml ?? t.xml, a = r.doctype ?? t.doctype;
568
567
  } else
569
- l = e, a = n.xml, o = n.doctype;
570
- a && (r.push(a), a.endsWith(`
571
- `) || r.push(`
572
- `)), o && (r.push(o), o.endsWith(`
573
- `) || r.push(`
568
+ l = e, s = t.xml, a = t.doctype;
569
+ s && (i.push(s), s.endsWith(`
570
+ `) || i.push(`
571
+ `)), a && (i.push(a), a.endsWith(`
572
+ `) || i.push(`
574
573
  `));
575
- const u = n.useCDataForScripts ?? !1, i = n.useCDataForStyles ?? !1, t = n.voidTrailingSlash ?? !0;
576
- return O(l, r, "HTML", u, i, t), r.join("");
574
+ const p = t.useCDataForScripts ?? !1, o = t.useCDataForStyles ?? !1, T = t.voidTrailingSlash ?? !0, n = t.attributeNaming ?? "eitherName";
575
+ return R(l, i, "HTML", p, o, T, n), i.join("");
577
576
  }
578
- function O(e, n, r, l, a, o) {
577
+ function R(e, t, i, l, s, a, p) {
579
578
  if (e != null) {
580
579
  if (typeof e == "string") {
581
- n.push(x(e, !1));
580
+ t.push(G(e, !1));
582
581
  return;
583
582
  }
584
583
  if (typeof e == "number" || typeof e == "bigint") {
585
- n.push(String(e));
584
+ t.push(String(e));
586
585
  return;
587
586
  }
588
587
  if (typeof e == "boolean") {
589
- n.push(String(e));
588
+ t.push(String(e));
590
589
  return;
591
590
  }
592
591
  if (Array.isArray(e)) {
593
- for (const u of e)
594
- O(u, n, r, l, a, o);
592
+ for (const o of e)
593
+ R(o, t, i, l, s, a, p);
595
594
  return;
596
595
  }
597
596
  if (typeof e != "function" && typeof e != "symbol" && !(e && typeof e == "object" && "then" in e && typeof e.then == "function") && e && typeof e == "object" && "type" in e && "props" in e) {
598
- J(e, n, r, l, a, o);
597
+ ie(e, t, i, l, s, a, p);
599
598
  return;
600
599
  }
601
600
  }
602
601
  }
603
- function J(e, n, r, l, a, o) {
604
- var y;
605
- const u = e.type;
606
- let i = r;
607
- if (u === "svg" ? i = "SVG" : u === "math" && (i = "MATHML"), n.push("<"), n.push(u), e.props) {
608
- for (const [A, b] of Object.entries(e.props))
609
- if (A !== "children" && !(b === !1 || b === null || b === void 0))
610
- if (b === !0)
611
- n.push(" "), n.push(A);
612
- else if (A === "style" && typeof b == "object") {
613
- const g = ee(b);
614
- g && (n.push(' style="'), n.push(x(g, !0)), n.push('"'));
615
- } else
616
- n.push(" "), n.push(A), n.push('="'), n.push(x(String(b), !0)), n.push('"');
617
- }
618
- const t = (y = e.props) == null ? void 0 : y.children;
619
- let c;
620
- if (t && typeof t == "object" && "then" in t && typeof t.then == "function" ? c = !1 : c = t != null && (Array.isArray(t) && t.length > 0 || !Array.isArray(t) && t !== !1), F.has(u))
621
- o ? n.push(" />") : n.push(">");
622
- else if (c) {
623
- n.push(">");
624
- const A = t;
625
- u === "script" && l || u === "style" && a ? (n.push("<![CDATA["), G(A, n, i, l, a, o), n.push("]]>")) : u === "script" || u === "style" ? W(A, n) : O(A, n, i, l, a, o), n.push("</"), n.push(u), n.push(">");
626
- } else Q.has(u), n.push("></"), n.push(u), n.push(">");
627
- }
628
- function G(e, n, r, l, a, o, u) {
602
+ function ie(e, t, i, l, s, a, p) {
603
+ var h;
604
+ const o = e.type;
605
+ let T = i;
606
+ if (o === "svg" ? T = "SVG" : o === "math" && (T = "MATHML"), t.push("<"), t.push(o), e.props)
607
+ for (const [g, E] of Object.entries(e.props)) {
608
+ if (g === "children" || E === !1 || E === null || E === void 0)
609
+ continue;
610
+ const N = se(g, p);
611
+ if (E === !0)
612
+ t.push(" "), t.push(N);
613
+ else if (g === "style" && typeof E == "object") {
614
+ const y = ne(E);
615
+ y && (t.push(' style="'), t.push(G(y, !0)), t.push('"'));
616
+ } else
617
+ t.push(" "), t.push(N), t.push('="'), t.push(G(String(E), !0)), t.push('"');
618
+ }
619
+ const n = (h = e.props) == null ? void 0 : h.children;
620
+ let r;
621
+ if (n && typeof n == "object" && "then" in n && typeof n.then == "function" ? r = !1 : r = n != null && (Array.isArray(n) && n.length > 0 || !Array.isArray(n) && n !== !1), $.has(o))
622
+ a ? t.push(" />") : t.push(">");
623
+ else if (r) {
624
+ t.push(">");
625
+ const g = n;
626
+ o === "script" && l || o === "style" && s ? (t.push("<![CDATA["), j(g, t, T, l, s, a, p), t.push("]]>")) : o === "script" || o === "style" ? Q(g, t) : R(g, t, T, l, s, a, p), t.push("</"), t.push(o), t.push(">");
627
+ } else K.has(o), t.push("></"), t.push(o), t.push(">");
628
+ }
629
+ function j(e, t, i, l, s, a, p, o) {
629
630
  if (e != null) {
630
631
  if (typeof e == "string") {
631
- n.push(Z(e));
632
+ t.push(J(e));
632
633
  return;
633
634
  }
634
635
  if (typeof e == "number" || typeof e == "bigint" || typeof e == "boolean") {
635
- n.push(String(e));
636
+ t.push(String(e));
636
637
  return;
637
638
  }
638
639
  if (Array.isArray(e)) {
639
- for (const i of e)
640
- G(i, n, r, l, a, o);
640
+ for (const T of e)
641
+ j(T, t, i, l, s, a, p);
641
642
  return;
642
643
  }
643
- O(e, n, r, l, a, o);
644
+ R(e, t, i, l, s, a, p);
644
645
  }
645
646
  }
646
- function W(e, n) {
647
+ function Q(e, t) {
647
648
  if (e != null) {
648
649
  if (typeof e == "string") {
649
- n.push(e);
650
+ t.push(e);
650
651
  return;
651
652
  }
652
653
  if (typeof e == "number" || typeof e == "bigint" || typeof e == "boolean") {
653
- n.push(String(e));
654
+ t.push(String(e));
654
655
  return;
655
656
  }
656
657
  if (Array.isArray(e)) {
657
- for (const r of e)
658
- W(r, n);
658
+ for (const i of e)
659
+ Q(i, t);
659
660
  return;
660
661
  }
661
662
  }
662
663
  }
663
- function ee(e) {
664
- const n = [];
665
- for (const [r, l] of Object.entries(e))
664
+ function ne(e) {
665
+ const t = [];
666
+ for (const [i, l] of Object.entries(e))
666
667
  if (l) {
667
- const a = $(r);
668
- n.push(`${a}: ${l}`);
668
+ const s = ee(i);
669
+ t.push(`${s}: ${l}`);
669
670
  }
670
- return n.join("; ");
671
- }
672
- function te(e) {
673
- const n = [];
674
- function r(l) {
675
- if (typeof l == "string" && n.push(l), (typeof l == "number" || typeof l == "bigint" || typeof l == "boolean") && n.push(`${l}`), typeof l == "object" && l !== null && "type" in l && l.props && "children" in l.props) {
676
- const a = l.props.children;
677
- if (l.type === "script" || l.type === "style" || l.type === "template" || a && typeof a == "object" && "then" in a && typeof a.then == "function")
671
+ return t.join("; ");
672
+ }
673
+ function ye(e) {
674
+ const t = [];
675
+ function i(l) {
676
+ if (typeof l == "string" && t.push(l), (typeof l == "number" || typeof l == "bigint" || typeof l == "boolean") && t.push(`${l}`), typeof l == "object" && l !== null && "type" in l && l.props && "children" in l.props) {
677
+ const s = l.props.children;
678
+ if (l.type === "script" || l.type === "style" || l.type === "template" || s && typeof s == "object" && "then" in s && typeof s.then == "function")
678
679
  return;
679
- if (Array.isArray(a))
680
- for (const o of a)
681
- r(o);
682
- else a != null && r(a);
680
+ if (Array.isArray(s))
681
+ for (const a of s)
682
+ i(a);
683
+ else s != null && i(s);
683
684
  }
684
685
  if (Array.isArray(l))
685
- for (const a of l)
686
- r(a);
686
+ for (const s of l)
687
+ i(s);
687
688
  }
688
- return r(e), n.join("");
689
+ return i(e), t.join("");
689
690
  }
690
- async function L(e) {
691
+ async function U(e) {
691
692
  if (e == null)
692
693
  return e;
693
694
  if (e && typeof e == "object" && "then" in e && typeof e.then == "function") {
694
- const n = await e;
695
- return L(n);
695
+ const t = await e;
696
+ return U(t);
696
697
  }
697
698
  if (typeof e == "string" || typeof e == "number" || typeof e == "boolean" || typeof e == "bigint")
698
699
  return e;
699
700
  if (typeof e != "function" && typeof e != "symbol") {
700
701
  if (Array.isArray(e))
701
702
  return await Promise.all(
702
- e.filter((r) => !(r == null || typeof r == "function" || typeof r == "symbol")).map((r) => L(r))
703
+ e.filter((i) => !(i == null || typeof i == "function" || typeof i == "symbol")).map((i) => U(i))
703
704
  );
704
705
  if (e && typeof e == "object" && "type" in e && "props" in e) {
705
- const n = e, r = {};
706
- for (const [l, a] of Object.entries(n.props))
706
+ const t = e, i = {};
707
+ for (const [l, s] of Object.entries(t.props))
707
708
  if (l === "children") {
708
- const o = await L(a);
709
- o != null && (r.children = o);
709
+ const a = await U(s);
710
+ a != null && (i.children = a);
710
711
  } else {
711
- if (typeof a == "function" || typeof a == "symbol")
712
+ if (typeof s == "function" || typeof s == "symbol")
712
713
  continue;
713
- a != null && (r[l] = a);
714
+ s != null && (i[l] = s);
714
715
  }
715
716
  return {
716
- type: n.type,
717
- props: r
717
+ type: t.type,
718
+ props: i
718
719
  };
719
720
  }
720
721
  }
721
722
  }
722
- function Y(e, n) {
723
+ const le = [
724
+ "br",
725
+ ["span", "class"],
726
+ "p",
727
+ ["a", "href", "rel", "class"],
728
+ "pre",
729
+ "del",
730
+ "code",
731
+ "em",
732
+ "strong",
733
+ "i",
734
+ "u",
735
+ "ul",
736
+ ["ol", "start", "reversed"],
737
+ ["li", "value"],
738
+ "blockquote"
739
+ ], ae = [
740
+ "h-*",
741
+ "p-*",
742
+ "u-*",
743
+ "dt-*",
744
+ "e-*",
745
+ "mention",
746
+ "hashtag",
747
+ "ellipsis",
748
+ "invisible"
749
+ ], oe = ["http", "https"], fe = {
750
+ a: ["href"],
751
+ area: ["href"],
752
+ audio: ["src"],
753
+ base: ["href"],
754
+ blockquote: ["cite"],
755
+ button: ["formaction"],
756
+ del: ["cite"],
757
+ embed: ["src"],
758
+ form: ["action"],
759
+ iframe: ["src"],
760
+ img: ["src", "longdesc"],
761
+ input: ["src", "formaction"],
762
+ ins: ["cite"],
763
+ link: ["href"],
764
+ object: ["data"],
765
+ q: ["cite"],
766
+ script: ["src"],
767
+ source: ["src"],
768
+ track: ["src"],
769
+ video: ["src", "poster"]
770
+ };
771
+ function ce(e) {
772
+ const t = /* @__PURE__ */ new Map();
773
+ let i = !1, l = /* @__PURE__ */ new Set(), s = !1;
774
+ for (const a of e)
775
+ if (typeof a == "string")
776
+ a === "*" ? i = !0 : t.set(a.toLowerCase(), {
777
+ allowed: !0,
778
+ allowedAttributes: /* @__PURE__ */ new Set(),
779
+ allowAllAttributes: !1
780
+ });
781
+ else {
782
+ const [p, ...o] = a, T = o.includes("*");
783
+ p === "*" ? (i = !0, T ? s = !0 : l = new Set(o.map((n) => n.toLowerCase()))) : t.set(p.toLowerCase(), {
784
+ allowed: !0,
785
+ allowedAttributes: T ? /* @__PURE__ */ new Set() : new Set(o.map((n) => n.toLowerCase())),
786
+ allowAllAttributes: T
787
+ });
788
+ }
789
+ return { configs: t, allowAll: i, universalAttrs: l, universalAllowAllAttrs: s };
790
+ }
791
+ function ue(e) {
792
+ return e.includes("*") ? { patterns: [], allowAll: !0 } : { patterns: e.map((i) => {
793
+ const s = "^" + i.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
794
+ return new RegExp(s);
795
+ }), allowAll: !1 };
796
+ }
797
+ function pe(e = {}) {
798
+ const t = e.allowedTags ?? le, i = e.allowedClasses ?? ae, l = e.allowedLinkProtocols ?? oe, s = e.attributeNaming ?? "reactName", a = ce(t), p = ue(i);
799
+ return {
800
+ tagConfigs: a.configs,
801
+ classPatterns: p.patterns,
802
+ protocols: new Set(l.map((o) => o.toLowerCase())),
803
+ attributeNaming: s,
804
+ allowAllClasses: p.allowAll,
805
+ allowAllTags: a.allowAll,
806
+ universalAttributes: a.universalAttrs,
807
+ universalAllowAllAttributes: a.universalAllowAllAttrs
808
+ };
809
+ }
810
+ function he(e, t, i) {
811
+ return i ? !0 : t.some((l) => l.test(e));
812
+ }
813
+ function me(e, t, i) {
814
+ return i ? e : e.split(/\s+/).filter((a) => a.length > 0).filter((a) => he(a, t, i)).join(" ");
815
+ }
816
+ function Te(e, t) {
817
+ const i = e.trim();
818
+ if (t.has(".")) {
819
+ if (i.startsWith("/") || i.startsWith("./") || i.startsWith("../") || i.startsWith("#") || i.startsWith("?"))
820
+ return !0;
821
+ const a = i.indexOf(":"), p = i.indexOf("/");
822
+ if (a === -1 || p !== -1 && p < a)
823
+ return !0;
824
+ }
825
+ const l = i.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):/);
826
+ if (!l || !l[1])
827
+ return t.has(".");
828
+ const s = l[1].toLowerCase();
829
+ return t.has(s);
830
+ }
831
+ function ge(e) {
832
+ return fe[e.toLowerCase()] ?? [];
833
+ }
834
+ function de(e, t, i, l) {
835
+ const s = {}, a = ge(e), p = i.allowAllAttributes || l.universalAllowAllAttributes, o = l.attributeNaming === "exactName" ? "class" : "className", T = l.attributeNaming === "exactName" ? "for" : "htmlFor";
836
+ for (const [n, r] of Object.entries(t)) {
837
+ if (n === "children")
838
+ continue;
839
+ const h = n.toLowerCase();
840
+ if (a.includes(h) && typeof r == "string" && !Te(r, l.protocols))
841
+ return null;
842
+ if ((n === "className" || n === "class") && typeof r == "string") {
843
+ if (p)
844
+ s[o] = r;
845
+ else if (i.allowedAttributes.has("class") || l.universalAttributes.has("class")) {
846
+ const g = me(r, l.classPatterns, l.allowAllClasses);
847
+ g && (s[o] = g);
848
+ }
849
+ continue;
850
+ }
851
+ if ((n === "htmlFor" || n === "for") && typeof r == "string") {
852
+ (p || i.allowedAttributes.has("for") || l.universalAttributes.has("for")) && (s[T] = r);
853
+ continue;
854
+ }
855
+ (p || i.allowedAttributes.has(h) || i.allowedAttributes.has(n) || l.universalAttributes.has(h) || l.universalAttributes.has(n)) && (s[n] = r);
856
+ }
857
+ return s;
858
+ }
859
+ function X(e, t) {
860
+ if (e == null || typeof e == "string" || typeof e == "number" || typeof e == "boolean" || typeof e == "bigint")
861
+ return e;
862
+ if (Array.isArray(e)) {
863
+ const o = [];
864
+ for (const T of e) {
865
+ const n = X(T, t);
866
+ Array.isArray(n) ? o.push(...n) : n != null && o.push(n);
867
+ }
868
+ return o.length === 0 ? [] : o.length === 1 ? o[0] : o;
869
+ }
870
+ const i = e, l = i.type.toLowerCase();
871
+ let s = t.tagConfigs.get(l);
872
+ !s && t.allowAllTags && (s = {
873
+ allowed: !0,
874
+ allowedAttributes: t.universalAttributes,
875
+ allowAllAttributes: t.universalAllowAllAttributes
876
+ });
877
+ const a = i.props.children !== void 0 ? X(i.props.children, t) : void 0;
878
+ if (!s) {
879
+ if (l === "img") {
880
+ const o = i.props.alt;
881
+ return typeof o == "string" && o.length > 0 ? o : void 0;
882
+ }
883
+ return a !== void 0 ? a : void 0;
884
+ }
885
+ const p = de(l, i.props, s, t);
886
+ if (p === null) {
887
+ if (l === "img") {
888
+ const o = i.props.alt;
889
+ if (typeof o == "string" && o.length > 0)
890
+ return o;
891
+ }
892
+ return a !== void 0 ? a : void 0;
893
+ }
894
+ return a !== void 0 && (p.children = a), {
895
+ type: i.type,
896
+ props: p
897
+ };
898
+ }
899
+ function Ae(e, t = {}) {
900
+ const i = pe(t);
901
+ return X(e, i);
902
+ }
903
+ function Y(e, t) {
723
904
  if (e == null || typeof e == "string" || typeof e == "number" || typeof e == "boolean" || typeof e == "bigint")
724
905
  return e;
725
906
  if (Array.isArray(e))
726
- return e.map((r) => Y(r, n));
907
+ return e.map((i) => Y(i, t));
727
908
  if (typeof e == "object" && "type" in e && "props" in e) {
728
- const { type: r, props: l } = e, { children: a, ...o } = l;
729
- if (a !== void 0) {
730
- const u = Y(a, n);
731
- return u === null ? n(r, o) : Array.isArray(u) ? n(r, o, ...u) : n(r, o, u);
909
+ const { type: i, props: l } = e, { children: s, ...a } = l;
910
+ if (s !== void 0) {
911
+ const p = Y(s, t);
912
+ return p === null ? t(i, a) : Array.isArray(p) ? t(i, a, ...p) : t(i, a, p);
732
913
  }
733
- return n(r, o);
914
+ return t(i, a);
734
915
  }
735
916
  return null;
736
917
  }
737
- function re(e) {
738
- return K(e);
918
+ function be(e, t = {}) {
919
+ return te(e, t);
920
+ }
921
+ function Ee(e, t = {}) {
922
+ return e && typeof e == "object" && "node" in e ? k(e, t) : e === void 0 ? "" : k(e, t);
739
923
  }
740
- function ne(e, n = {}) {
741
- return e && typeof e == "object" && "node" in e ? H(e, n) : e === void 0 ? "" : H(e, n);
924
+ async function we(e) {
925
+ return await U(e);
742
926
  }
743
- async function ie(e) {
744
- return await L(e);
927
+ function Ne(e, t = {}) {
928
+ return Ae(e, t);
745
929
  }
746
930
  export {
747
- ie as awaitHtmlNode,
748
- w as decodeHtmlEntities,
749
- x as encodeHtmlEntities,
750
- te as getTextContent,
931
+ we as awaitHtmlNode,
932
+ O as decodeHtmlEntities,
933
+ G as encodeHtmlEntities,
934
+ ye as getTextContent,
751
935
  Y as htmlNodeTo,
752
- re as readHtml,
753
- ne as writeHtml
936
+ be as readHtml,
937
+ Ne as safeHtml,
938
+ Ee as writeHtml
754
939
  };
package/dist/parser.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { ParseResult } from './types.ts';
2
- export declare function parseHtml(html: string): ParseResult;
1
+ import { ParseResult, ParserOptions } from './types.ts';
2
+ export declare function parseHtml(html: string, options?: ParserOptions): ParseResult;
@@ -0,0 +1,15 @@
1
+ import { HtmlNode, SafeHtmlOptions } from './types.ts';
2
+ /**
3
+ * Sanitizes an HtmlNode tree by removing disallowed tags, attributes, and URLs.
4
+ *
5
+ * - Tags not in allowedTags have their content retained (folded into parent)
6
+ * - Images replaced with their alt text when removed
7
+ * - Attributes not in the tag's allowed list are dropped
8
+ * - Classes are filtered by allowedClasses patterns (supports wildcards like 'h-*')
9
+ * - URLs not matching allowedLinkProtocols cause the element to be removed
10
+ * - Use '.' as a protocol to allow relative URLs
11
+ * @param node - The HtmlNode to sanitize
12
+ * @param options - The SafeHtmlOptions to use
13
+ * @returns The sanitized HtmlNode
14
+ */
15
+ export declare function safeHtml(node: HtmlNode, options?: SafeHtmlOptions): HtmlNode;
package/dist/types.d.ts CHANGED
@@ -1,14 +1,26 @@
1
+ /**
2
+ * Style attribute as a structured record.
3
+ */
1
4
  export interface HtmlStyle {
2
5
  [key: string]: string;
3
6
  }
7
+ /**
8
+ * Properties of an HtmlElement.
9
+ */
4
10
  export interface HtmlElement {
5
11
  type: string;
6
12
  props: HtmlProps;
7
13
  }
14
+ /**
15
+ * HtmlElement properties
16
+ */
8
17
  export interface HtmlProps {
9
18
  [key: string]: string | number | boolean | HtmlStyle | HtmlNode | Promise<HtmlNode>;
10
19
  children?: HtmlNode | Promise<HtmlNode>;
11
20
  }
21
+ /**
22
+ * Nodes will be parsed into one of these types.
23
+ */
12
24
  export type HtmlNode = HtmlElement | string | number | bigint | boolean | null | undefined | HtmlNode[];
13
25
  export declare enum ParserState {
14
26
  TEXT = "TEXT",
@@ -29,6 +41,9 @@ export declare enum ParserState {
29
41
  SCRIPT_CONTENT = "SCRIPT_CONTENT",
30
42
  STYLE_CONTENT = "STYLE_CONTENT"
31
43
  }
44
+ /**
45
+ * Namespace of an element.
46
+ */
32
47
  export declare enum Namespace {
33
48
  HTML = "HTML",
34
49
  SVG = "SVG",
@@ -45,10 +60,71 @@ export interface ParseResult {
45
60
  doctype?: string;
46
61
  node: HtmlNode | HtmlNode[];
47
62
  }
63
+ /**
64
+ * Controls how special attributes like 'class' and 'for' are named:
65
+ * - 'reactName': Use React-style names (className, htmlFor) - default for parsing
66
+ * - 'exactName': Use exact HTML names (class, for)
67
+ */
68
+ export type ParserAttributeNaming = 'reactName' | 'exactName';
69
+ /**
70
+ * Controls how special attributes are written:
71
+ * - 'reactName': Write as React-style (className, htmlFor)
72
+ * - 'exactName': Write as exact HTML (class, for)
73
+ * - 'eitherName': Normalize className->class, htmlFor->for (default)
74
+ */
75
+ export type WriterAttributeNaming = 'reactName' | 'exactName' | 'eitherName';
76
+ export interface ParserOptions {
77
+ /**
78
+ * How to name special attributes like 'class' and 'for'.
79
+ * - 'reactName' (default): Convert to React-style (className, htmlFor)
80
+ * - 'exactName': Keep exact HTML names (class, for)
81
+ */
82
+ attributeNaming?: ParserAttributeNaming;
83
+ }
48
84
  export interface WriterOptions {
49
85
  useCDataForScripts?: boolean;
50
86
  useCDataForStyles?: boolean;
51
87
  xml?: string;
52
88
  doctype?: string;
53
89
  voidTrailingSlash?: boolean;
90
+ /**
91
+ * How to write special attributes like 'class' and 'for'.
92
+ * - 'eitherName' (default): Normalize className->class, htmlFor->for
93
+ * - 'reactName': Write as-is (className, htmlFor)
94
+ * - 'exactName': Write as exact HTML (class, for)
95
+ */
96
+ attributeNaming?: WriterAttributeNaming;
97
+ }
98
+ /**
99
+ * Allowed tag specification:
100
+ * - string: tag name with no custom attributes allowed (only global attrs like 'class' if classes are allowed)
101
+ * - [tagName, ...attrs]: tag name with specific allowed attributes
102
+ */
103
+ export type AllowedTag = string | [string, ...string[]];
104
+ /**
105
+ * Options for the safeHtml function.
106
+ */
107
+ export interface SafeHtmlOptions {
108
+ /**
109
+ * List of allowed tags. Can be strings (tag name only) or tuples [tagName, ...allowedAttributes].
110
+ * If not provided, uses default safe tags.
111
+ */
112
+ allowedTags?: AllowedTag[];
113
+ /**
114
+ * List of allowed CSS class patterns. Supports wildcards like 'h-*', 'p-*'.
115
+ * If not provided, uses default allowed classes.
116
+ */
117
+ allowedClasses?: string[];
118
+ /**
119
+ * List of allowed URL protocols for links/media. Use '.' for relative URLs.
120
+ * If not provided, uses default ['http', 'https'].
121
+ */
122
+ allowedLinkProtocols?: string[];
123
+ /**
124
+ * The attribute naming convention used in the input.
125
+ * - 'reactName' (default): Input uses React-style names (className, htmlFor)
126
+ * - 'exactName': Input uses exact HTML names (class, for)
127
+ * When set, also affects how the output is named.
128
+ */
129
+ attributeNaming?: ParserAttributeNaming;
54
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@levischuck/tiny-html",
3
- "version": "0.0.4",
3
+ "version": "0.1.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.js",